﻿using Flare.Controls;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace Flare.Pages.Reports
{
    public partial class NetworkMap : UserControl, IPubTypicalPage, INotifyPropertyChanged
    {
        public string name
        {
            get { return "Карта сети"; }
        }

        double transScale = 1;

        public double TransScale
        {
            get {
                return transScale;
            }
            set {
                transScale = value;
                PropertyChanged(this, new PropertyChangedEventArgs("TransScale"));
            }
        }
        
        Dictionary<int, IPointControl> points = new Dictionary<int, IPointControl>();
        List<LineFromPointToPoint> lines = new List<LineFromPointToPoint>();

        public NetworkMap()
        {
            InitializeComponent();      
     
            GenerateMaps();

            this.SizeChanged += (s, e) => {
                GenerateZoom();
            };
        }

        void GenerateZoom() {

            double x = Math.Round((rootScroll.ActualHeight / root.ActualHeight), 1);
            double y = Math.Round((rootScroll.ActualWidth / root.ActualWidth), 1);
            if (x > y)
            {
                TransScale = (y > 1) ? 1 : y - 0.05;
            }
            else
            {
                TransScale = (x > 1) ? 1 : x - 0.05;
            }
        }
        void GenerateMaps()
        {
            var gen_map = new DB.endpoints_map().Index();

            foreach (var p in gen_map)
            {
                if (p.dev_type != NetworkPointType.line)
                {
                    CreateNetworkPoint(p.dev_name, p.dev_type, p.pointA_X, p.pointB_Y, p.id, p.dev_ip);
                    Debug.WriteLine(string.Format("create point {0} {1} {2} {3}", p.dev_type, p.pointA_X, p.pointB_Y, p.dev_ip));
                }
            }

            foreach (var p in gen_map)
            {
                if (p.dev_type == NetworkPointType.line)
                {
                    CreateLine((int)p.pointA_X, (int)p.pointB_Y, true);
                }
            }
        }
        void CreateLine(int A, int B, bool IsLoad = false)
        {
            if (lines.Contains(new LineFromPointToPoint() { PointA = A, PointB = B }) || lines.Contains(new LineFromPointToPoint() { PointA = B, PointB = A }))
            {
                return;
            }

            IPointControl pointA = points[A];
            IPointControl pointB = points[B];

            Line _line = new Line();

            _line.X1 = pointA.CenterPoint.X;
            _line.Y1 = pointA.CenterPoint.Y;

            _line.X2 = pointB.CenterPoint.X;
            _line.Y2 = pointB.CenterPoint.Y;

            _line.Stroke = Brushes.DarkGray;
            _line.StrokeDashArray = new DoubleCollection() { 2 };
            _line.StrokeThickness = 1;

            pointA.eMoveCenterPoint += (X, Y) =>
            {
                _line.X1 = X;
                _line.Y1 = Y;
            };

            pointB.eMoveCenterPoint += (X, Y) =>
            {
                _line.X2 = X;
                _line.Y2 = Y;
            };

            pointA.eRemove += (s, e) =>
            {
                root.Children.Remove(_line);
                lines.Remove(new LineFromPointToPoint() { PointA = pointA.ID, PointB = pointB.ID });
            };

            pointB.eRemove += (s, e) =>
            {
                root.Children.Remove(_line);
                lines.Remove(new LineFromPointToPoint() { PointA = pointA.ID, PointB = pointB.ID });
            };

            Canvas.SetZIndex(_line, -1);

            root.Children.Add(_line);
            lines.Add(new LineFromPointToPoint() { PointA = pointA.ID, PointB = pointB.ID });

            if (IsLoad == false)
            {
                DB.Entity.EndpointMap data = new DB.Entity.EndpointMap();
                data.dev_type = NetworkPointType.line;
                data.pointA_X = pointA.ID;
                data.pointB_Y = pointB.ID;
                new DB.endpoints_map().Create(data);
            }

        }
        void CreateNetworkPoint(string name, NetworkPointType type, double left_position, double top_position, int? dic_num = null, string ip = null)
        {
            Controls.NetworkPoint point = new NetworkPoint(name, left_position, top_position, type);

            if (dic_num.HasValue)
            {
                point = new NetworkPoint(name, left_position, top_position, type, ip);
                point.ID = dic_num.Value;
            }
            else
            {
                point = new NetworkPoint(name, left_position, top_position, type, ip);
                DB.Entity.EndpointMap data = new DB.Entity.EndpointMap();
                data.dev_ip = ip;
                data.dev_name = name;
                data.dev_type = type;
                data.pointA_X = left_position;
                data.pointB_Y = top_position;
                int? id = new DB.endpoints_map().Create(data);
                if (id.HasValue)
                {
                    point.ID = id.Value;
                }
                else
                {
                    return;
                }
            }

            root.Children.Add(point);
            points.Add(point.ID, point);

        }
        private void root_Drop(object sender, System.Windows.DragEventArgs e)
        {
            DragDropNetPointInfo data = (DragDropNetPointInfo)e.Data.GetData(typeof(DragDropNetPointInfo));
            CreateNetworkPoint(data.name, data.type, e.GetPosition(root).X, e.GetPosition(root).Y);
        }
        private void hub_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            DragDrop.DoDragDrop((sender as Image), new DragDropNetPointInfo() { name = "Хаб", type = NetworkPointType.hub }, DragDropEffects.Move);
            e.Handled = true;
        }
        private void vpn_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            DragDrop.DoDragDrop((sender as Image), new DragDropNetPointInfo() { name = "Роутер", type = NetworkPointType.vpn }, DragDropEffects.Move);
            e.Handled = true;
        }
        private void server_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            DragDrop.DoDragDrop((sender as Image), new DragDropNetPointInfo() { name = "Сервер", type = NetworkPointType.server }, DragDropEffects.Move);
            e.Handled = true;
        }
        private void cloud_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            DragDrop.DoDragDrop((sender as Image), new DragDropNetPointInfo() { name = "Канал связи", type = NetworkPointType.cloud }, DragDropEffects.Move);
            e.Handled = true;
        }

        int? PointA, PointB;
        private void root_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.Source is IPointControl && PointA.HasValue && PointA != PointB)
            {
                PointB = (e.Source as IPointControl).ID;
                CreateLine(PointA.Value, PointB.Value);
            }
            else
            {
                PointA = null;
                PointB = null;
            }
        }
        private void root_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.Source is IPointControl)
            {
                PointA = (e.Source as IPointControl).ID;
                PointB = null;
            }
            else
            {
                PointA = null;
                PointB = null;
            }
        }

        void ExportMapsToJpeg()
        {
            SaveFileDialog file_select = new SaveFileDialog();
            file_select.Filter = "PNG Files(*.png)|*.png";

            Nullable<bool> result = file_select.ShowDialog();
            string fileName = string.Empty;

            if (result == true)
            {
                RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)root.ActualWidth, (int)root.ActualHeight, 96d, 96d, PixelFormats.Pbgra32);

                root.Measure(new Size((int)root.ActualWidth, (int)root.ActualHeight));
                root.Arrange(new Rect(new Size((int)root.ActualWidth, (int)root.ActualHeight)));
                renderBitmap.Render(root);

                PngBitmapEncoder encoder = new PngBitmapEncoder();

                encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
                using (FileStream file = File.Create(file_select.FileName))
                {
                    encoder.Save(file);
                }
            }
        }
        private void Save_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ExportMapsToJpeg();
            e.Handled = true;
        }
        struct LineFromPointToPoint
        {
            public int PointA { get; set; }
            public int PointB { get; set; }
        }
        struct DragDropNetPointInfo
        {
            public string name { get; set; }
            public NetworkPointType type { get; set; }
        }
        struct NrtworkPointEntity
        {
            public int? id { get; set; }
            public NetworkPointType type_ep { get; set; }
            public string name { get; set; }
            public double X_OR_PointA { get; set; }
            public double Y_OR_PointB { get; set; }
        }

        public void SetSearchString(string _content) { }
        public void CreateStartMenu()
        {
           // object[] images = new object[] { new FunctionalPanelItems().Insert(glob.PageNames.network_create), };
           // glob.kernel.CreateFunctionalPanel(images);
        }

        private void AutoGenerateMap_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            int x = 64;
            foreach (var m in new DB.endpoints_map().MapGenerate()) {

                NetworkPointType currenttype = NetworkPointType.cloud;
                switch (m.id_type)
                {
                    case  2:
                        currenttype = NetworkPointType.server;
                        break;

                    case 4:
                        currenttype = NetworkPointType.vpn;
                        break;

                    default:
                        currenttype = NetworkPointType.cloud;
                        break;
                }

                CreateNetworkPoint(m.name, currenttype, x, 0, null, m.net_ip);
                x = x + 68;
            }
        }
        
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
    }
}
